package com.dingteam.question.common.validation.module;

import com.dingteam.model.Result;
import com.dingteam.question.common.dto.QuestionPaperVerifyDTO;
import com.dingteam.question.common.dto.QuestionResultVerifyDTO;
import com.dingteam.question.common.enums.ModuleEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 复合校验
 * @author Jamin
 * @date 2019/08/14
 */
@Slf4j
@Component
public class CompositeModuleValidator implements ModuleValidator {

	@Autowired
	private ListableBeanFactory beanFactory;

	private Map<ModuleEnum, ModuleValidator> validatorMap;

	@Override
	public ModuleEnum getModule() {
		// 实际执行时不需要获取当前控件类型，传入的枚举参数就是当前的组件类型
		return null;
	}

	@Override
	public boolean supportModule(ModuleEnum moduleEnum) {
		boolean present = reallyValidator(moduleEnum).isPresent();
		if (!present) {
			log.error("unsupported module enum:{}", moduleEnum);
		}
		return present;
	}

	@Override
	public Result<String> createValid(QuestionPaperVerifyDTO.QuestionItemDTO itemDTO) {
		ModuleEnum moduleEnum = ModuleEnum.valueOfAlias(itemDTO.getModuleType());
		Optional<ModuleValidator> validator = reallyValidator(moduleEnum);
		if (validator.isPresent()) {
			return validator.get().createValid(itemDTO);
		}
		throw new IllegalArgumentException("unsupported module enum");
	}

	@Override
	public Result<String> submitValid(QuestionResultVerifyDTO.ItemResultDTO item) {
		ModuleEnum moduleEnum = item.getModuleEnum();
		Optional<ModuleValidator> validator = reallyValidator(moduleEnum);
		if (validator.isPresent()) {
			return validator.get().submitValid(item);
		}
		throw new IllegalArgumentException("unsupported module enum");
	}

	@PostConstruct
	public void init() {
		this.validatorMap = validatorMap();
	}

	private Map<ModuleEnum, ModuleValidator> validatorMap() {
		List<ModuleValidator> list = new ArrayList<>(beanFactory.getBeansOfType(ModuleValidator.class).values());
		list.remove(this);
		return list.stream()
			.collect(Collectors.toConcurrentMap(ModuleValidator::getModule, Function.identity(), (k1, k2) -> k1));
	}

	private Optional<ModuleValidator> reallyValidator(ModuleEnum moduleEnum) {
		if (null == this.validatorMap) {
			this.validatorMap = validatorMap();
		}
		return Optional.ofNullable(this.validatorMap.get(moduleEnum));
	}
}
